from datetime import datetime, timedelta

import jwt
from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware
from applications.configs.common import JWT_SECRET, ALGORITHM, EXCLUDED_PATHS, ACCESS_TOKEN_EXPIRE_MINUTES
from jwt.exceptions import PyJWTError

from applications.configs.func import render_template
from applications.models import Session
from applications.models.users import Users


# 用户验证中间件
class JwtMiddleware(BaseHTTPMiddleware):

    async def dispatch(self, request: Request, call_next):
        paths = str(request.url.path).split("/")
        request.state.user = None
        # 排除静态文件
        if paths[1] not in ['static']:
            # 检查当前请求路径是否在排除列表中
            if request.url.path not in EXCLUDED_PATHS:
                try:
                    authorization = request.headers.get("Authorization")
                    # 获取请求头数据
                    if not authorization:
                        token = request.cookies.get("Authorization")
                    else:
                        token = authorization.removeprefix("Bearer ")
                    if not token:
                        return render_template(request, "/login.html")

                    payload = jwt.decode(token, JWT_SECRET, algorithms=[ALGORITHM])
                    id: int = payload.get("id")
                    if id is None:
                        return render_template(request, "/login.html")
                    # 查询用户信息
                    session = Session()
                    try:

                        user = session.query(Users).filter_by(id=id).first()

                    except:
                        return render_template(request, "/login.html")

                    finally:
                        session.close()

                    if not user:
                        return render_template(request, "/login.html")

                    request.state.user = user
                except (KeyError, IndexError, PyJWTError):
                    return render_template(request, "/login.html")

        return await call_next(request)


# 生成Token
def create_jwt_token(data: dict):
    payload = data.copy()
    payload.update({'exp': datetime.now() + timedelta(hours=ACCESS_TOKEN_EXPIRE_MINUTES)})
    return jwt.encode(payload, JWT_SECRET, algorithm=ALGORITHM)